package com.lyx.router.processor;

import com.google.auto.service.AutoService;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.lyx.router.annotations.Destination;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
import java.util.Collections;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.JavaFileObject;

@AutoService(Processor.class)
public class DestinationProcessor extends AbstractProcessor {

    private static final String TAG = "DestinationProcessor";

    /**
     * 告诉编译器当前处理器支持的注解类型
     */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return Collections.singleton(Destination.class.getCanonicalName());
    }

    /**
     * 编译器找到我们关心的注解后，会回调这个方法
     */
    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {

        // 避免多次调用process
        if (roundEnvironment.processingOver()) {
            return false;
        }

        System.out.println(TAG + ">>> process start");


        String rootDir = processingEnv.getOptions().get("root_project_dir");


        // 获取所有标记了 Destination注解 的类的信息
        Set<Element> allDestination = (Set<Element>) roundEnvironment.getElementsAnnotatedWith(Destination.class);

        System.out.println(TAG + ">>> allDestination size:" + allDestination.size());

        // 当未收集到@Destination注解的时候，跳过后续流程
        if (allDestination.size() < 1) {
            return false;
        }

        // 将要自动生成的类的类名
        String className = "RouterMapping_" + System.currentTimeMillis();

        StringBuilder sb = new StringBuilder();
        sb.append("package com.lyx.router.mapping;\n\n");
        sb.append("import java.util.HashMap;\n");
        sb.append("import java.util.Map;\n\n");
        sb.append("public class ").append(className).append(" {\n\n");
        sb.append("    public static Map<String, String> get() {\n\n");
        sb.append("        Map<String, String> mapping = new HashMap<>();\n\n");

        final JsonArray destinationJsonArray = new JsonArray();

        // 遍历所有注解信息，挨个获取详细信息
        for (Element element : allDestination) {
            final TypeElement typeElement = (TypeElement) element;
            final Destination destination = typeElement.getAnnotation(Destination.class);
            if (destination == null) {
                continue;
            }
            final String url = destination.url();
            final String desc = destination.description();
            final String realPath = typeElement.getQualifiedName().toString();

            sb.append("        mapping.put(");
            sb.append("\"" + url + "\"").append(", ");
            sb.append("\"" + realPath + "\"").append(");\n\n");


            System.out.println(TAG + ">>> url :" + url + "   desc:" + desc + "   realPath:" + realPath);

            JsonObject item = new JsonObject();
            item.addProperty("url", url);
            item.addProperty("description", desc);
            item.addProperty("realPath", realPath);

            destinationJsonArray.add(item);

        }

        sb.append("        return mapping;\n\n");
        sb.append("    }\n\n");
        sb.append("}\n\n");

        String mappingFullClassName = "com.lyx.router.mapping." + className;

        System.out.println(TAG + ">>> \nmappingFullClassName:" + mappingFullClassName);
        System.out.println(TAG + ">>> \n\n" + sb);

        // 写入自动生成的类到本地文件中
        try {
            JavaFileObject source = processingEnv.getFiler().createSourceFile(mappingFullClassName);
            Writer writer = source.openWriter();
            writer.write(sb.toString());
            writer.flush();
            writer.close();
        } catch (Exception e) {
            throw new RuntimeException("Error while create file!!!");
        }

        // 写入JSON到本地文件中 start

        // 检测父目录是否存在
        File rootDirFile = new File(rootDir);
        if (!rootDirFile.exists()) {
            throw new RuntimeException("root_project_dir not exist!!!");
        }

        File routerFileDir = new File(rootDirFile, "router_mapping");
        if (!routerFileDir.exists()) {
            routerFileDir.mkdir();
        }

        File mappingFile = new File(routerFileDir, "mapping_" + System.currentTimeMillis() + ".json");

        // 写入json内容
        try {
            BufferedWriter out = new BufferedWriter(new FileWriter(mappingFile));
            String jsonStr = destinationJsonArray.toString();
            out.write(jsonStr);
            out.flush();
            out.close();
        } catch (Throwable throwable) {
            throw new RuntimeException("Error while write json", throwable);
        }

        System.out.println(TAG + ">>> process finish");

        return false;
    }

}
